<?php
/**
 ***********************************************************************************************************************
 * 所有品牌运单号规则
 ***********************************************************************************************************************
 */
namespace soa\check\waybill;

use artisan\cache;
use soa\common\RemoteDB;
use soa\partner\ane\BaseInformation;
use soa\partner\kj\KjClient;
use soa\partner\zt\ztCommon;

class Rule
{
    protected $rule = null;

    protected $brand = '';

    protected $data = [];

    protected $forceUpdate = false;

    protected $cacheKey = null;

    protected $availableBrand = [
        'sto' => '申通',
        'zt'  => '中通',
        'zto' => '中通',
        'ane' => '安能',
        'qf'  => '全峰',
        'kj'  => '快捷快递',
        'gt'  => '国通',
    ];

    /*
        1.268,368,468,568,668,768,868,968开头，12位数字，普通面单
        2.588开头，12位数字，到付单
        3.688开头，12位数字，保价单
        4.888开头，12位数字，最早期的淘宝专用面单，现在只作为普通面单使用
        5.11开头，12位数字，代收货款面单
        6.22开头，12位数字，普通电子面单
        7.33/44/55/66/77/88/99开头，13位数字(除去668和888开头的)，菜鸟电子面单，第十三位是校验码
        8.900开头，12位数字，申通大条码
        9.STO开头，12位，铅封号
        10.新增12位单号，4开头，但是44开头除外
    */
//    protected $stoRule = [
    public $stoRule = [
        'verify' => [
            '/^(sto|STO|[2-9]68)\d{9}$/',
            '/^(588|688|888|900|((11|22)\d{1})|((33|44|55|77|99)\d{2})|((66|88)([0-7]|9)\d{1}))\d{9}$/',
        ],
        'free'   => [
//            '/^4[012356789][0-9]{10}$/',
//            '/^((Z\d{11})|(HD80\d{8})|(9[89]00\d{8})|((536|317)\d{9})|(D990\d{8})|(4[012356789][0-9]{10}))$/',
//            '/^(((HD80|9[89]00|D990)\d{8})|((536|317)\d{9}$)|(4[012356789]\d{10})|(Z\d{11}))$/',
            '/^(((9[89]00)\d{8})|((536|317)\d{9}$)|(4[012356789]\d{10}))$/', 
        ],
        'order'  => [
//            '/^(22[^79]\w{9})|(118\w{9,10})|((33|55|77)\w{11})$/',
//            '/^(56\d{12})|(3131\d{10})|(315\d{11})|(560\d{9})|(543\d{9})|(319\d{11})|(22[^79]\d{9})|(118\d{9,10})|((33|55|77)\d{11})$/',
            '/^(((560|543|22[^79])\d{9})|(118\d{9,10})|(3131\d{10})|((315|319|(33|55|77))\d{11})|(56\d{12}))$/',
        ],
    ];

    /**
    //2017-08-25新增一批sto单号规则
    //319	[0-9]{11}	14	电子面单
    //317	[0-9]{9}	12	纸质面单
    //D990	[0-9]{8}	12	纸质面单
    //543	[0-9]{9}	12	电子面单
    //560	[0-9]{9}	12	电子面单
    //536	[0-9]{9}	12	纸质面单
    //9800	[0-9]{8}	12	纸质面单
    //9900	[0-9]{8}	12	纸质面单
    //315	[0-9]{11}	14	电子面单
    //3131	[0-9]{10}	14	电子面单
    //56	[0-9]{12}	14	电子面单
    //HD80	[0-9]{8}	12	纸质面单
    //Z	[0-9]{11}	12	纸质面单

     */

    /**
        1、8-16位数字（现在主要的面单就是1-9开头 12位数字的）
        2、9位数字+1位大写字母
        3、3位数字+1位大写字母+9位数字
        4、6或10开头+7位数字
        5、(2|8|9|KB|SK)+8位数字
        6、01+6位数字
        7、a+13至14位数字
        8、13+6位数字
        9、14+6位数字
        10、2位大写字母+13位数字
        11、S+9位数字+(字符'-')+P1
        12、6205+11位数字
        13、14位数字+C+1位数字
        14、SY00+8位数字
        15、17+11位数字
        16、SHZC+11位数字
        17、HK+7至9位数字
        18、14位数字+1位大写或小写字母+1位数字
        19、HQ+12位数字
        20、JY+13位数字
        21、B+13位数字+C
        22、SSCZC+12位数字
        23、12位数字+(字符'-')+1位数字
        24、SSXZC+12位数字
        25、HY+8至16位数字
     */
    protected $qfRule = [
        'generalRule' => '^(kb|KB|kB|Kb)?\d{8,12}$',//我们自己写的
        'fromGt' => '^([0-9]{10,11})$|^([0-9]{12,13})$|^([0-9]{9}[A-Z]{1})$|^([0-9]{3}[A-Z]{1}[0-9]{9})$|^((6|10)[0-9]{7})$|^((2|8|9|KB|SK)[0-9]{8})$|^(01[0-9]{6})$|^(a[0-9]{13,14})$|^(13[0-9]{6})$|^([0-9]{15})$|^(14[0-9]{6})$|^([A-Z]{2}[0-9]{13})$|^([0-9]{8,14})$|^([0-9]{15,16})$|^(S[0-9]{9}[-]{1}P1)$|^(6205[0-9]{11})$|^([0-9]{14}C[1-9]{1})$|^(SY00[0-9]{8})$|^(17[0-9]{11})$|^(SHZC[0-9]{11})$|^(HK[0-9]{7,9})$|^([0-9]{14}[a-z,A-Z]{1}[0-9]{1})$|^(HQ[0-9]{12})$|^(JY[0-9]{13})$|^(B[0-9]{13}C)$|^(SSCZC([0-9]{12}|[0-9]{12}-[0-9]{1}))$|^(SSXZC[0-9]{12})$|^(HY[0-9]{8,16})$|^([A-Z]{2}[0-9]{11}-[0-9]{1}-[0-9]{1}-)$',//国通提供的
    ];

    /**
        1开头10位（包裹标签）
        2开头10位（现付）
        3开头10位（非淘电子面单）
        4开头10位、12位（菜鸟面单）
        5开头10位（纸质电子面单）
        5开头12位（京东电子面单）
        6开头10位（到付）
        7开头10位（广东五联单）
        8开头10位（回单）
        9开头10位（内部单）
     */
    protected $gtRule = [
        'generalRule' => '^(((2|3|4|5|6|7|8|9)\d{9})|(2|4|5)\d{11})$',
    ];

    public function __construct($brand = '', $data = [])
    {
        $this->brand    = $brand;
        $this->data     = $data;
        $this->cacheKey = $this->brand . 'Rules:rule_express';
    }

    /**
     * @param bool $forceUpdate
     * @return array|null
     */
    public function getRule($forceUpdate = false)
    {
        if(!isset($this->availableBrand[$this->brand])) {
            return [];
//            raise(1401, '抱歉，您所属快递公司获取不到运单号规则！');
        }

        $this->forceUpdate = $forceUpdate;

        if(empty($this->forceUpdate) && $this->rule){
            return $this->rule;
        }else{
            $method = 'get' . ucfirst($this->brand) . 'Rule';
            $rule = $this->$method();
            if(is_array($rule) && $rule){
                $this->rule = $rule;
            }
            return $rule;
        }
    }

    /**
     * @return array
     */
    public function getStoRule()
    {
        $stoRule = $this->stoRule;

        $generalRule = $generalRule2 = $thermalRule = [];
        foreach($stoRule['order'] as $v){
            $generalRule[] = str_replace(['/'], '', $v);
            $thermalRule[] = str_replace(['/'], '', $v);
        }
        foreach($stoRule['free'] as $v){
            $generalRule[] = str_replace(['/'], '', $v);
        }

        foreach($stoRule['verify'] as $v){
            $generalRule2[] = str_replace(['/'], '', $v);
        }

        $returnRules = [
            'generalRule'  => empty($generalRule) ? '': implode('|',$generalRule),//此规则APP通过后直接true
            'generalRule2' => empty($generalRule2) ? '': implode('|',$generalRule2),//此规则APP通过后还需要验证单号某个数字
            'thermalRule'  => empty($thermalRule) ? '' : implode('|',$thermalRule),
        ];
        cache::set($this->cacheKey,$returnRules,3600);
        return $returnRules;
    }

    /**
     * @return array
     */
    public function getZtRule()
    {
        $ztRule = $this->ztRule();

        $returnRules = [
            'generalRule' => !empty($ztRule['rule_express']) ? $ztRule['rule_express'] : '',
            'thermalRule' => !empty($ztRule['rule_order']) ? $ztRule['rule_order'] : '',
        ];
        return $returnRules;
    }

    /**
     * @return array
     */
    public function getZtoRule()
    {
        return $this->getZtRule();
    }

    /**
     * @return array|bool|mixed|null|string
     */
    public function getAneRule()
    {
        $aneRule = $this->aneRule();

        $generalRule = $thermalRule = [];
        if($aneRule && is_array($aneRule)){
            foreach($aneRule as $item){
                if(!empty($item['ewbRuleValue']) && !empty($item['ewbTypeName'])){
                    if('主单' == $item['ewbTypeName']){
                        $generalRule[] = $item['ewbRuleValue'];
                    }
                }
            }
            if(!empty($generalRule)){
                $generalRule = implode('|', $generalRule);
            }
        }

        $returnRules = $this->buildReturn($generalRule, $thermalRule);

        return $returnRules;
    }

    /**
     * @return array
     */
    public function getQfRule()
    {
        $generalRule = $thermalRule = $this->qfRule['generalRule'] . '|'  .$this->qfRule['fromGt'];
        return $this->buildReturn($generalRule, $thermalRule);
    }

    /**
     * @return array
     */
    public function getGtRule()
    {
        //国通和全峰有合作，支持全峰单号规则
        $generalRule = $thermalRule = $this->gtRule['generalRule'];
        return $this->buildReturn($generalRule, $thermalRule);
    }

    /**
     * @return array
     */
    public function getKjRule()
    {
        $kjRule = $this->kjRule();

        $generalRule = $thermalRule = [];
        if($kjRule && is_array($kjRule)){
            foreach($kjRule as $item){
                if(!empty($item['baseCode']) && !empty($item['baseValue'])){
                    if(in_array($item['baseCode'],['bill_rule','bill_el_rule'])){
                        $generalRule[] = $item['baseValue'];
                    }
                }
            }
            if(!empty($generalRule)){
                $generalRule = implode('|', $generalRule);
            }
        }

        return $this->buildReturn($generalRule, $thermalRule);
    }

    public function stoRule()
    {

    }

    /**
     * @return array|bool|mixed|null|string
     */
    public function ztRule()
    {
        $backupKey = $this->cacheKey . '_Backup';
        if(empty($this->forceUpdate)) {
            $ztRule = cache::get($this->cacheKey);
        }
        if(empty($ztRule['rule_order'])){
            if(empty($this->data)){
                $this->data = (new RemoteDB('kd_pda', 'tbl_scan_courier_zt'))->getOne(array('switch' => 'on', 'state' => 'approve','key !='=>'0000000000','emp_no !='=>''),'id desc');
            }
            $phone = !empty($this->data['username']) ? $this->data['username'] : $this->data['cm_phone'];
            $ret = (new ztCommon())->ztXMLInterface($phone,['optype'=>'G010'],0);
            if(!empty($ret['Success']['d']['p'])){
                $ztRule = [
                    'rule_express' => !empty($ret['Success']['d']['p']['c']) ? $ret['Success']['d']['p']['c'] . '|' . $ret['Success']['d']['p']['a'] : $ret['Success']['d']['p']['a'],
                    'rule_bag'     => $ret['Success']['d']['p']['b'],
                    'rule_order'   => $ret['Success']['d']['p']['c'],
                ];
                cache::set($this->cacheKey,$ztRule,3600);
                cache::set($backupKey,$ztRule,86400*3);
            }
        }

        if(empty($ztRule['rule_order'])){
            $rulesBackup = cache::get($backupKey);
            $ztRule = empty($rulesBackup) ? [] : $rulesBackup;
        }

        return $ztRule;
    }

    /**
     * @return array
     */
    public function aneRule()
    {
        return (new BaseInformation())->getRule($this->forceUpdate);
    }

    /**
     * @return array
     */
    public function kjRule()
    {
        return (new KjClient())->getRule($this->forceUpdate);
    }

    /**
     * @param $generalRule
     * @param $thermalRule
     * @return array
     */
    public function buildReturn($generalRule, $thermalRule)
    {
        return [
            'generalRule' => !empty($generalRule) ? $generalRule : '',
            'thermalRule' => !empty($thermalRule) ? $thermalRule : '',
        ];
    }
}
